﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using PGMHelper;
using WSAP;

namespace CouplingBeamProject
{
    //结构
    class Structure
    {
        /// <summary>
        /// 列表储存楼层
        /// </summary>
        private List<ComponentBasic> StoreyList { set; get; }

        /// <summary>
        /// 所有楼层所有节点列表
        /// </summary>
        private List<Node> NodeList { set; get; }

        /// <summary>
        /// 有限元模型
        /// </summary>
        private WModelNet Model { set; get; }

        /// <summary>
        /// 结构高度
        /// </summary>
        public double StructHeight
        {
            get
            {
                 return (from node in this.NodeList select node.Y).ToList().Max();
            }
        }
        
        /// <summary>
        /// 获得最小层高
        /// </summary>
        public double MinStoreyHeight
        {
            get
            {
                return (from storey in this.StoreyList select storey.StoreyHeight).ToList().Min();
            }
        }

        /// <summary>
        /// 最小梁高
        /// </summary>
        public double MinBeamHeight
        {
            get
            {
                return (from storey in this.StoreyList select storey.MiddleBeamHeight).ToList().Min();
            }
        }

        /// <summary>
        /// 楼层数据（楼层号和层高）
        /// </summary>
        public GridViewDatas StoreyData
        {
            get
            {
                var storeylist = this.StoreyList;
                var data = new GridViewDatas("楼层信息");
                data.Add(new GridViewColumn(storeylist.GetPropertyList("StoreyID").ConvertAll(d => (int)d), titleName: "层号", width: 140));
                data.Add(new GridViewColumn(storeylist.GetPropertyList("StoreyHeight").ConvertAll(d => (double)d), titleName: "层高", width: 140));
                return data;
            }
        }

        /// <summary>
        /// 清空
        /// </summary>
        /// <returns></returns>
        public GridViewDatas Clear()
        {
            StoreyList.Clear();
            return this.StoreyData;
        }

        /// <summary>
        /// 添加联肢剪力墙楼层（组件）
        /// </summary>
        /// <param name="leftWallWidth"></param>
        /// <param name="middleBeamWidth"></param>
        /// <param name="rightWallWidth"></param>
        /// <param name="middleBeamHeigth"></param>
        /// <param name="storeyHeight"></param>
        /// <returns></returns>
        public void AddStoreyInfo(double leftWallWidth, double middleBeamWidth, double rightWallWidth, double middleBeamHeigth, double storeyHeight)
        {
            this.StoreyList.Add(new CoupledShearWall(StoreyList.Count + 1, leftWallWidth, middleBeamWidth, rightWallWidth, middleBeamHeigth, storeyHeight) 
            {
                
            });
        }

        /// <summary>
        /// 添加带拉缝填充墙楼层（组件）
        /// </summary>
        /// <param name="leftWallWidth"></param>
        /// <param name="middleBeamWidth"></param>
        /// <param name="rightWallWidth"></param>
        /// <param name="middleBeamHeigth"></param>
        /// <param name="storeyHeight"></param>
        /// <param name="leftInfillWidth"></param>
        /// <param name="rightInfillWidth"></param>
        /// <param name="downInfillHeight"></param>
        /// <returns></returns>
        public void AddStoreyInfo(double leftWallWidth, double middleBeamWidth, double rightWallWidth, double middleBeamHeigth,
            double storeyHeight, double leftInfillWidth, double rightInfillWidth, double downInfillHeight)
        {
            this.StoreyList.Add(new CoupledShearWallWithInfill(StoreyList.Count + 1, leftWallWidth, middleBeamWidth, rightWallWidth, middleBeamHeigth,
            storeyHeight, leftInfillWidth, rightInfillWidth, downInfillHeight)
            {

            });
        }

        /// <summary>
        /// 网格划分
        /// </summary>
        public void Mesh(double MiddleBeamThicknessFactor)
        {
            //Y向偏移
            double Yoffset = 0;
            //依次网格剖分
            this.StoreyList.ForEach(storey =>
            {
                storey.Mesh(Yoffset,MiddleBeamThicknessFactor);
                Yoffset += storey.GetHeight();
            });
            //节点过滤
            this.NodeFilter();
        }

        /// <summary>
        /// 节点过滤
        /// </summary>
        public void NodeFilter()
        {
            List<Node> OriginNodeList = new List<Node>();
            this.NodeList = new List<Node>();
            //提取全部楼层的节点
            this.StoreyList.ForEach(Storey => OriginNodeList.AddRange(Storey.GetNodeList()));
            //初始化字典
            var dict = new Dictionary<double, Dictionary<double, Node>>();
            //函数指针是否存在相同节点
            Func<Node, bool> isSameNodeExist = (node) =>
            {
                //是否存在
                if (!dict.ContainsKey(node.X))
                {
                    dict.Add(node.X, new Dictionary<double, Node> { { node.Y, node } });
                    return false;
                }
                else if (!dict[node.X].ContainsKey(node.Y))
                {
                    dict[node.X].Add(node.Y, node);
                    return false;
                }
                else node.Index = dict[node.X][node.Y].Index;
                return true;
            };
            //过滤相同节点
            foreach (var originnode in OriginNodeList)
            {
                //节点已存在
                if (isSameNodeExist(originnode))
                    continue;
                //赋予编号
                originnode.Index = this.NodeList.Count + 1;
                this.NodeList.Add(originnode);
            }
        }

        /// <summary>
        /// 建立有限元模型
        /// </summary>
        public bool SetWModelNet(double MiddleBeamThicknessFactor)
        {
            this.Mesh(MiddleBeamThicknessFactor);
            //实例化
            this.Model = new WModelNet();
            //添加节点
            this.NodeList.ForEach(node => Model.AddNode(node.Index, node.X, 0.0, node.Y));
            //荷载系数
            var loadFactor = GlobalVar.MaxLoad / this.StructHeight;
            //遍历加载点获得各个点加载力
            this.StoreyList.ForEach(Storey => Storey.AddNodeLoad(this.Model, this.NodeList, loadFactor));
            //添加单元
            foreach (var storey in this.StoreyList)
            {
                if (!storey.AddElements(Model)) return false;
                if (GlobalVar.isRigidFloor)
                    storey.AddRigidFrames(Model, this.NodeList);
            }
            //约束Z坐标为0的点
            this.Model.FixZ(0.0);
            return true;
        }

        /// <summary>
        /// 有限元求解分析
        /// </summary>
        public bool Analysis()
        {
            //创建有限元模型
            if (!this.Model.CreateFEModel(false)) return this.Model.ShowWarningError();

            var element = this.Model.GetElements();
            //求解
            //this.Model.DoLinearStaticAnalyze();
            if (!this.Model.DoLinearStaticAnalyze()) return this.Model.ShowWarningError();
            //绘图
            this.Model.ToGraphics(new StructrueChartParam
            {
                DOF = 1,
                isNodeMaxResponseShow = true,
                ChartType = StructureChartType.GeneralStatic,
            });
            return true;
        }

        /// <summary>
        /// 获得最大响应
        /// </summary>
        /// <returns></returns>
        public double GetMaxResponse(double MiddleBeamThicknessFactor)
        {
            //创建有限元模型
            this.SetWModelNet(MiddleBeamThicknessFactor);
            //创建有限元模型
            if (!this.Model.CreateFEModel(false))
            {
                this.Model.ShowWarningError();
                return 0;
            }
            //求解
            if (!this.Model.DoLinearStaticAnalyze())
            {
                this.Model.ShowWarningError();
                return 0;
            }
            var disp = this.Model.GetMaxNodeResponse(this.StructHeight);

            this.Model.Dispose();
            GC.Collect();
            // 最大位移
            return disp;
        }

        ///// <summary>
        ///// 输入目标位移，获得等效弹模放大倍数
        ///// </summary>
        ///// <param name="targetresponse"></param>
        ///// <param name="beamHeight"></param>
        ///// <returns></returns>
        //private double GetEquivalModulusfactor(double targetresponse, double beamHeight)
        //{
        //    //弹模放大倍数基数
        //    var ElaModfacBase = GlobalVar.ElasticModulusFactorBase;
        //    double DownfactorLimit = 1;
        //    double UpfactorLimit = ElaModfacBase;
        //    double Average = 0;
        //    double tol = GlobalVar.GetEquilibrumBeamHeigthTol;
        //    double error = 1;
        //    //计算边界位移
        //    var disp = new Structure(this, beamHeight, ElaModfacBase).GetMaxResponse();
        //    //边界位移不满足直接返回
        //    if(disp > targetresponse)
        //    {
        //        MessageBoxExtern.Error("GlobalVar.ElasticModulusFactorBase未能满足需求");
        //        return -1;
        //    }
        //    while (error > tol)
        //    {
        //        Average = (UpfactorLimit + DownfactorLimit) / 2;
        //        //以下限值为梁高建立等效梁模型并求解位移
        //        var DownLimitStructure = new Structure(this, beamHeight, DownfactorLimit);
        //        var downresponse = DownLimitStructure.GetMaxResponse();
        //        //以平均值为梁高建立等效梁模型并求解位移
        //        var AveLimitStructure = new Structure(this, beamHeight, Average);
        //        var averesponse = AveLimitStructure.GetMaxResponse();
        //        //如果目标位移介于计算结果之间，则取平均值为上边界;否则取平均值为下边界
        //        if ((downresponse - targetresponse) * (averesponse - targetresponse) < 0)
        //        {
        //            UpfactorLimit = Average;
        //        }
        //        else
        //        {
        //            DownfactorLimit = Average;
        //        }
        //        //计算梁高为上下边界平均值时的误差
        //        error = Math.Abs((averesponse - targetresponse) / targetresponse);
        //    }
        //    //返回平均值为等效弹模放大倍数
        //    return Average;
        //}

        ///// <summary>
        ///// 输入目标位移，获得等效梁高
        ///// </summary>
        ///// <returns></returns>
        //public Tuple<double, double> GetEquivalResult()
        //{
        //    //计算目标响应
        //    var targetresponse = this.GetMaxResponse();
        //    //定义上下边界，容差，误差初始值
        //    double DownLimit = this.MinBeamHeight;
        //    //上边界是否符合最小限值
        //    if(this.MinStoreyHeight * GlobalVar.BeamHeightLimitRatio < DownLimit)
        //    {
        //        MessageBoxExtern.Error("GlobalVar.BeamHeightLimitRatio过小");
        //        return Tuple.Create<double, double>(-1, -1);
        //    }
        //    double UpLimit = this.MinStoreyHeight * GlobalVar.BeamHeightLimitRatio; 
        //    double Average = 0;
        //    double tol = GlobalVar.GetEquilibrumBeamHeigthTol;
        //    double error = 1;
        //    //计算边界位移
        //    var maxStruct = new Structure(this, UpLimit);
        //    var disp = maxStruct.GetMaxResponse();
        //    //位移越界直接计算弹模、
        //    if(disp > targetresponse)
        //    {
        //        var ERatio = this.GetEquivalModulusfactor(targetresponse, UpLimit);
        //        return Tuple.Create<double, double>(UpLimit, ERatio);
        //    }
        //    //二分法计算等效梁高度
        //    while (error > tol && Math.Abs(UpLimit- DownLimit) >  tol * this.MinStoreyHeight)
        //    {
        //        Average = (DownLimit + UpLimit) / 2;
        //        //以下限值为梁高建立等效梁模型并求解位移
        //        var DownLimitStructure = new Structure(this, DownLimit);
        //        var downresponse = DownLimitStructure.GetMaxResponse();
        //        //以平均值为梁高建立等效梁模型并求解位移
        //        var AveLimitStructure = new Structure(this, Average);
        //        var averesponse = AveLimitStructure.GetMaxResponse();
        //        //如果目标位移介于计算结果之间，则取平均值为上边界;否则取平均值为下边界
        //        if ((downresponse - targetresponse) * (averesponse - targetresponse) < 0)
        //        {
        //            UpLimit = Average;
        //        }
        //        else
        //        {
        //            DownLimit = Average;
        //        }
        //        //计算梁高为上下边界平均值时的误差
        //        error = Math.Abs((averesponse - targetresponse) / targetresponse);
        //    }
        //    //返回平均值为等效梁高度
        //    return Tuple.Create<double, double>(Average, 1); 
        //}

        /// <summary>
        /// 输入目标位移，获得等效梁尺寸放大系数
        /// </summary>
        /// <returns></returns>
        public double GetEquivalResult()
        {
            //计算目标响应
            var targetresponse = this.GetMaxResponse(1);
            //定义上下边界，容差，误差初始值
            double DownLimitBeamHeight = this.MinBeamHeight;
            double UpLimitBeamHeight = this.MinStoreyHeight * GlobalVar.BeamHeightLimitRatio;
            double DownLimit = 1;
            double UpLimit = UpLimitBeamHeight / DownLimitBeamHeight;
            //double DownLimitBeamThick = GlobalVar.Thickness;
            //double UpLimitBeamThick = UpLimit * DownLimitBeamThick;
            double AverageBeamHeight;
            double Ave = 0;
            //上边界是否符合最小限值
            if (UpLimit < DownLimit)
            {
                MessageBoxExtern.Error("GlobalVar.BeamHeightLimitRatio过小");
                return -1;
            }            
            double tol = GlobalVar.GetEquilibrumBeamHeigthTol;
            double error = 1;
            //计算边界位移
            var maxStruct = new Structure(this, UpLimitBeamHeight);
            var disp = maxStruct.GetMaxResponse(UpLimit);
            //位移越界直接计算输出最大值
            if (disp > targetresponse)
            {
                return UpLimit;
            }
            //二分法计算等效梁尺寸放大系数
            while (error > tol && Math.Abs(UpLimitBeamHeight - DownLimitBeamHeight) > tol * this.MinStoreyHeight)
            {
                AverageBeamHeight = (UpLimitBeamHeight + DownLimitBeamHeight) / 2;
                //AveragrBeamThick = (UpLimitBeamThick + DownLimitBeamThick) / 2;
                Ave = AverageBeamHeight / this.MinBeamHeight;
                //以下限值放大梁截面尺寸建立等效梁模型并求解位移
                var DownLimitStructure = new Structure(this, DownLimitBeamHeight);
                var downresponse = DownLimitStructure.GetMaxResponse(DownLimit);
                //以平均值放大梁截面尺寸建立等效梁模型并求解位移
                var AveLimitStructure = new Structure(this, AverageBeamHeight);
                var averesponse = AveLimitStructure.GetMaxResponse(Ave);
                //如果目标位移介于计算结果之间，则取平均值为上边界;否则取平均值为下边界
                if ((downresponse - targetresponse) * (averesponse - targetresponse) < 0)
                {
                    UpLimitBeamHeight = AverageBeamHeight;
                }
                else
                {
                    DownLimitBeamHeight = AverageBeamHeight;
                    DownLimit = Ave;
                }
                //计算梁高为上下边界平均值时的误差
                error = Math.Abs((averesponse - targetresponse) / targetresponse);
            }
            //返回平均值为等效梁尺寸放大系数
            return Ave;
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        public Structure()
        {
            this.StoreyList = new List<ComponentBasic>();
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="struc"></param>
        public Structure(Structure struc, double middleBeamHeight)
        {
            this.StoreyList = new List<ComponentBasic>();
            struc.StoreyList.ForEach(storey => this.StoreyList.Add(new CoupledShearWall(storey, middleBeamHeight)));
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="struc"></param>
        public Structure(Structure struc, double middleBeamHeigth, double ElasticModulusFactor)
        {
            this.StoreyList = new List<ComponentBasic>();
            struc.StoreyList.ForEach(storey => this.StoreyList.Add(new CoupledShearWall(storey, middleBeamHeigth, ElasticModulusFactor)));
        }
    }
}
